package com.bdbit.ChargingStation.services;

import com.bdbit.ChargingStation.wx.WxConfig;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;

/**
 * 微信支付服务
 *
 * @author sheng
 */
@Service
@Slf4j
public class WXPayService {
    private final Gson gson = new GsonBuilder().serializeNulls().create();
    
    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * JSAPI支付场景(微信内置浏览器打开的网页)或小程序支付场景，商户需调用该接口在微信支付下单，生成用于调起支付的预支付交易会话标识(prepay_id)。
     */
    public String wxPayJsapi(String openId, String outTradeNo, String totalAmount) throws IOException {
        JsapiServiceExtension jsapiService = new JsapiServiceExtension.Builder().config(WxConfig.getConfig()).build();
        PrepayRequest request = new PrepayRequest();

        // 总金额: 订单总金额，单位为分，整型。
        // 示例：1元应填写 100
        Amount amount = new Amount();
        amount.setTotal(new BigDecimal(totalAmount).multiply(new BigDecimal(100)).intValue());
        request.setAmount(amount);

        request.setAppid(WxConfig.appid);
        request.setMchid(WxConfig.merchantId);
        request.setDescription("充电桩服务");
        request.setNotifyUrl("https://tiaozhuan.siji.pro/api/order/wxpayNotify");
        request.setOutTradeNo(outTradeNo);

        Payer payer = new Payer();
        payer.setOpenid(openId);
        request.setPayer(payer);

        PrepayWithRequestPaymentResponse response = jsapiService.prepayWithRequestPayment(request);
        System.out.println(gson.toJson(response));
        return gson.toJson(response);
    }
    
    /**
     * 微信支付退款
     * @param orderId 订单号
     * @param refundAmount 退款金额（元为单位）
     * @return 退款是否成功
     */
    public boolean refund(String orderId, BigDecimal refundAmount) {
        try {
            // 创建退款服务
            RefundService refundService = new RefundService.Builder().config(WxConfig.getConfig()).build();
            
            // 构建退款请求
            CreateRequest request = new CreateRequest();
            request.setOutTradeNo(orderId);
            request.setOutRefundNo("refund_" + orderId + "_" + System.currentTimeMillis());
            request.setReason("充电桩服务中断退款");
            
            // 退款金额信息
            AmountReq amountReq = new AmountReq();
            // 查询原订单金额（数据库中存储的是分为单位）
            BigDecimal originalAmountInCents = getOriginalOrderAmount(orderId);
            if (originalAmountInCents == null) {
                log.error("获取原订单金额失败: orderId={}", orderId);
                return false;
            }
            
            // 验证退款金额不能超过原订单金额
            BigDecimal originalAmountInYuan = originalAmountInCents.divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
            if (refundAmount.compareTo(originalAmountInYuan) > 0) {
                log.error("退款金额超过原订单金额: orderId={}, refundAmount={}元, originalAmount={}元", 
                        orderId, refundAmount, originalAmountInYuan);
                return false;
            }
            
            // 转换为分为单位（微信支付要求）
            long totalAmountCents = originalAmountInCents.longValue();
            long refundAmountCents = refundAmount.multiply(new BigDecimal(100)).longValue();
            
            log.info("退款金额计算: 原订单={}分({}元), 退款={}元={}分", 
                    totalAmountCents, originalAmountInYuan, refundAmount, refundAmountCents);
            
            amountReq.setTotal(totalAmountCents);
            amountReq.setRefund(refundAmountCents);
            amountReq.setCurrency("CNY");
            request.setAmount(amountReq);
            
            // 发起退款请求
            Refund result = refundService.create(request);
            
            // 检查退款结果
            log.info("微信退款请求结果: {}", gson.toJson(result));
            
            // 根据退款状态判断是否成功
            String status = result.getStatus().toString();
            boolean isSuccess = "SUCCESS".equals(status) || "PROCESSING".equals(status);
            
            if (isSuccess) {
                log.info("微信退款成功或处理中: orderId={}, refundAmount={}元, status={}", 
                        orderId, refundAmount, status);
            } else {
                log.error("微信退款失败: orderId={}, refundAmount={}元, status={}", 
                        orderId, refundAmount, status);
            }
            
            return isSuccess;
        } catch (ServiceException e) {
            log.error("微信退款服务异常: orderId={}, refundAmount={}元, code={}, message={}", 
                    orderId, refundAmount, e.getErrorCode(), e.getErrorMessage(), e);
            return false;
        } catch (Exception e) {
            log.error("微信退款异常: orderId={}, refundAmount={}元", orderId, refundAmount, e);
            return false;
        }
    }
    
    /**
     * 获取原订单金额（返回分为单位）
     * @param orderId 订单号
     * @return 订单金额（分为单位）
     */
    private BigDecimal getOriginalOrderAmount(String orderId) {
        try {
            // 从charging_order表查询订单金额（数据库存储的是元为单位12312）
            String sql = "SELECT prepay_amount FROM charging_order WHERE order_id = ? OR id = ? LIMIT 1";
            
            BigDecimal amountInYuan = jdbcTemplate.queryForObject(sql, BigDecimal.class, orderId, orderId);
            
            // 转换为分为单位（微信支付要求）
            BigDecimal amountInCents = amountInYuan.multiply(new BigDecimal(100));
            
            log.info("查询到订单金额: orderId={}, amount={}元={}分", orderId, amountInYuan, amountInCents);
            return amountInCents;
        } catch (EmptyResultDataAccessException e) {
            log.warn("未找到订单: orderId={}", orderId);
            
            // 尝试查询另一个可能的表
            try {
                String fallbackSql = "SELECT prepay_amount FROM orders WHERE order_id = ? LIMIT 1";
                BigDecimal amount = jdbcTemplate.queryForObject(fallbackSql, BigDecimal.class, orderId);
                log.info("从备用表查询到订单金额: orderId={}, amount={}分", orderId, amount);
                return amount;
            } catch (Exception fallbackEx) {
                log.error("从备用表查询订单金额失败: orderId={}", orderId, fallbackEx);
                return null;
            }
        } catch (Exception e) {
            log.error("查询订单金额失败: orderId={}", orderId, e);
            return null;
        }
    }
}
